﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.ServiceModel;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Win32;
using WikiBotDll;
using WikiBotWpf.WCFClient;
using Page = WikiBotDll.Page;

namespace WikiBotWpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private WCFClient.WikiBrodscyWcfServiceClient client = new WCFClient.WikiBrodscyWcfServiceClient();

        private readonly WikiBot bot = new WikiBot();

        /// <summary>Воркер обработки страниц
        /// </summary>
        private readonly BackgroundWorker worker = new BackgroundWorker();

        /// <summary>Количество обработанных страниц
        /// </summary>
        private int processedpages;

        public MainWindow()
        {
            InitializeComponent();
            worker.WorkerReportsProgress = true;
            worker.DoWork += backgroundWorker1_DoWork;
            worker.ProgressChanged += backgroundWorker1_ProgressChanged;
            worker.WorkerSupportsCancellation = true;
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        }

        /// <summary>Завершение воркера
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            prProcess.Value = 0;
            try
            {
                btnProcess.Content = "Start";
                tbNowProcessing.Text = "Processed " + processedpages + " pages";
            }
            catch (Exception exception)
            {
                tbNowProcessing.Text += exception.Message;
            }
        }

        /// <summary>Подключить бота
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Connect(object sender, RoutedEventArgs e)
        {
            try
            {
                try
                {
                    Cursor = Cursors.Wait;
                    client = new WikiBrodscyWcfServiceClient();
                    client.Open();                    
                }
                catch (EndpointNotFoundException ex)
                {
                    MessageBox.Show("Сервис по адресу " + txtbxServerName.Text + " не найден", "Ошибка подключения", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Ошибка подключения", MessageBoxButton.OK, MessageBoxImage.Error);
                }

                try
                {
                    client.ConnectBotToServer(txtbxServerName.Text, txtbxUserName.Text, pswdbxPassword.Password, 10);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Ошибка подключения:");
                }
            }
            finally
            {
                Cursor = Cursors.Arrow;
            }
        }

        /// <summary>Получить список страниц
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            //lbxPageNames.Items.Clear();
            //foreach (object pageName in bot.Pages)
            //{
            //    lbxPageNames.Items.Add(pageName);
            //}
        }

        /// <summary>Добавить слово
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddWord_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(txtbxnewWord.Text))
                return;
            //ищем чекбос с заданным именем и, если не находим, добавляем
            bool founded = false;
            foreach (object child in spWordList.Children)
            {
                var chbx = (child as CheckBox);
                if (chbx != null)
                {
                    if (chbx.Content.ToString() == txtbxnewWord.Text)
                        founded = true;
                }
            }

            if (!founded)
            {
                AddWordToPanel(txtbxnewWord.Text);
            }
        }

        /// <summary>Получить список слов с панели
        /// </summary>
        /// <returns></returns>
        private WikiWords GetWordsFromPanel()
        {
            var words = new WikiWords(bot.Site);

            foreach (object word in spWordList.Children)
            {
                var chbxtmp = word as CheckBox;
                if (chbxtmp != null && !string.IsNullOrEmpty(chbxtmp.Content as string) && chbxtmp.IsChecked == true)
                    words.Values.Add(chbxtmp.Content as string);
                words.LinkPageName = txtbxLinkPage.Text;
            }
            return words;
        }

        /// <summary>Запустить воркер линкования по страницам (замена слова ссылкой на статью)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProcessClick(object sender, RoutedEventArgs e)
        {
            //if (!worker.IsBusy)
            //{
            //    #region Проверка входных данных

            //    if ((txtbxLinkPage.Text == ""))
            //        return;
            //    processedpages = 0;
            //    if (bot == null || !bot.Connected)
            //    {
            //        MessageBox.Show("бот не подключен");
            //        return;
            //    }
            //    if (bot.Pages == null || bot.Pages.Count() == 0)
            //    {
            //        MessageBox.Show("Список страниц пуст");
            //        return;
            //    }

            //    #endregion

            //    prProcess.Maximum = bot.Pages.Count();
            //    var args = new ProcessPageArgs
            //                   {
            //                       Plist = bot.Pages,
            //                       Words = GetWordsFromPanel()
            //                   };

            //    #region Проверка параметров

            //    if (string.IsNullOrEmpty(args.Words.LinkPageName))
            //    {
            //        MessageBox.Show("Не указано, на что заменять");
            //        return;
            //    }

            //    if (args.Words == null || args.Words.Values.Count == 0)
            //    {
            //        MessageBox.Show("Не задан список слов");
            //        return;
            //    }

            //    #endregion

            //    worker.RunWorkerAsync(args);
            //    btnProcess.Content = "Stop";
            //}

            //else
            //{
            //    worker.CancelAsync();
            //}
        }

        /// <summary>Отображение процесса линкования
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_ProgressChanged(object sender,
                                                       ProgressChangedEventArgs e)
        {
            prProcess.Value = e.ProgressPercentage;
            try
            {
                tbNowProcessing.Text = (string) e.UserState;
            }
            catch (Exception exception)
            {
                tbNowProcessing.Text = exception.Message;
            }
        }

        /// <summary>Воркер обработки страниц
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            #region validate input params
            var backgroundWorker = sender as BackgroundWorker;
            if (backgroundWorker == null)
                throw new ArgumentException("sender");
            var args = (ProcessPageArgs) e.Argument;
            if (args == null || args.Words == null || args.Words.Values.Count <= 0)
                throw new ArgumentException("e.Argument");
            #endregion

            processedpages = 0;

            args.Words.Values.Sort();
            args.Words.Values.Reverse();

            foreach (Page page in args.Plist)
            {
                if (worker.CancellationPending)
                    return;
                if (WikiBot.ProcessPage(page, args.Words))
                    backgroundWorker.ReportProgress(++processedpages, page.title);
            }
        }

        /// <summary>Сохранить список слов в файл
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSaveWords_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new SaveFileDialog
                          {
                              Filter = "XML Files(*.xml)|*.xml",
                              DefaultExt = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName),
                              FileName = txtbxLinkPage.Text
                              
                          };
            if (dlg.ShowDialog() == true)
            {
                var a = GetWordsFromPanel();
                if (Path.GetFileName(dlg.FileName) != a.LinkPageName)
                {
                    MessageBox.Show("имя файла должно быть " + a.LinkPageName);
                    return;
                }
                a.SaveWordsToXml(Path.GetDirectoryName(dlg.FileName));
            }
        }

        /// <summary>Загрузить слова из файла
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLoadWords_Click(object sender, RoutedEventArgs e)
        {
            var dlg = new OpenFileDialog
                          {
                              Filter = "XML Files(*.xml)|*.xml",
                              DefaultExt = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)

                          };
            if (dlg.ShowDialog() == true)
            {
                spWordList.Children.Clear();
                var words = new WikiWords(bot.Site);
                words.LoadWordsFromXml(dlg.FileName);
                PutWordsToPanel(words);
            }
        }

        /// <summary>Загрузить в панель слов слова по списку
        /// </summary>
        /// <param name="words">Список слов</param>
        private void PutWordsToPanel(IEnumerable<string> words)
        {
            if (words == null) throw new ArgumentNullException("words");

            spWordList.Children.Clear();
            foreach (string word in words)
            {
                AddWordToPanel(word);
            }
        }

        /// <summary>Загрузить в панель слов слова по списку
        /// </summary>
        /// <param name="wikiWords"></param>
        private void PutWordsToPanel(WikiWords wikiWords)
        {
            #region validate input params
            if (wikiWords == null || wikiWords.Values == null || wikiWords.LinkPageName == null)
                throw new ArgumentNullException("wikiWords");
            #endregion

            PutWordsToPanel(wikiWords.Values, wikiWords.LinkPageName);
        }

        /// <summary>Загрузить в панель слов слова по списку и ссылку на статью
        /// </summary>
        /// <param name="words"></param>
        /// <param name="linkPageName"></param>
        private void PutWordsToPanel(IEnumerable<string> words, string linkPageName)
        {
            #region validate input params
            if (words == null) throw new ArgumentNullException("words");
            if (string.IsNullOrEmpty(linkPageName)) throw new ArgumentNullException("linkPageName");
            #endregion

            PutWordsToPanel(words);
            PutLinkToPanel(linkPageName);
        }

        /// <summary>Загрузить в панель ссылку на страницу
        /// </summary>
        /// <param name="linkPage"></param>
        private void PutLinkToPanel(String linkPage)
        {
            if (linkPage == null) throw new ArgumentNullException("linkPage");
            txtbxLinkPage.Text = linkPage;
        }

        /// <summary>Добавить на панель слов слово
        /// </summary>
        /// <param name="word">Добавляемое слово</param>
        private void AddWordToPanel(string word)
        {
            if (string.IsNullOrEmpty(word)) throw new ArgumentNullException("word");

            var chbx = new CheckBox {IsChecked = true, Content = word,};
            chbx.KeyDown += WordCheckBox_KeyDown;
            spWordList.Children.Add(chbx);
        }

        /// <summary>Удаляем чекбокс при нажатии на del
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WordCheckBox_KeyDown(object sender, KeyEventArgs e)
        {
            var chbx = sender as CheckBox;
            if (chbx != null)
            {
                if (e.Key == Key.Delete)
                {
                    var par = chbx.Parent as StackPanel;
                    if (par != null)
                    {
                        int n = par.Children.IndexOf(chbx);
                        par.Children.Remove(chbx);
                        if (par.Children.Count > 0)
                            if (--n > 0)
                                par.Children[n].Focus();
                            else
                                par.Children[0].Focus();
                    }
                }
            }
        }

        /// <summary>Если enter - добавляем слово
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtbxnewWord_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                btnAddWord_Click(sender, e);
            }
        }

        #region Nested type: ProcessPageArgs

        /// <summary>Класс аргументов для передачи в воркер линка
        /// </summary>
        public class ProcessPageArgs
        {
            private List<string> words = new List<string>();
            public PageList Plist { get; set; }

            public WikiWords Words { get; set; }
        }

        #endregion

        /// <summary>экспорт xml в веб
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (!bot.Connected)
            {
                bot.Connect(txtbxServerName.Text, txtbxUserName.Text, pswdbxPassword.Password);
            }

            var dlg = new OpenFileDialog
            {
                Filter = "XML Files(*.xml)|*.xml",
                DefaultExt = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)

            };


            if (dlg.ShowDialog() == true)
            {
                var infos = new DirectoryInfo(Path.GetDirectoryName(dlg.FileName)).GetFiles("*.xml");
                foreach (var fileInfo in infos)
                {
                    if (fileInfo.Name != "log4net.xml")
                        try
                        {
                            var words = new WikiWords(bot.Site);
                            words.LoadWordsFromXml(fileInfo.FullName);
                            words.SaveToPage();
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message);
                        }
                }
            }
        }

       

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            //PutWordsToPanel(bot.LoadWordsFromPage(txtbxLinkPage.Text + WikiBot.DictionaryAppendix));
        }

        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            var a = GetWordsFromPanel();
            a.SaveToPage();
        }

        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
            if (!bot.Connected)
            {
                bot.Connect(txtbxServerName.Text,txtbxUserName.Text,pswdbxPassword.Password);
            }
            bot.LoadListOfAllPages();
            bot.Dictionary.Load(bot.Pages);
            lstbxDicNames.Items.Clear();

            foreach (var wikiWords in bot.Dictionary.Words)
            {
                lstbxDicNames.Items.Add(new ListBoxItem(){Content = wikiWords.LinkPageName});
            }
        }

        private void Expander_Expanded(object sender, RoutedEventArgs e)
        {

        }

        private void Button_Click_5(object sender, RoutedEventArgs e)
        {
            try
            {
                client = new WCFClient.WikiBrodscyWcfServiceClient();
                client.EnableDictionaryWorker(true);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Ошибка " + ex.Message, "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error);
            }

        }

        private void Button_Click_6(object sender, RoutedEventArgs e)
        {
            client.EnableDictionaryWorker(false);
        }

        private void lstbxDicNames_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //lbx.Items.Clear();            

            //foreach (var wikiWord in bot.Dictionary.Words[lstbxDicNames.SelectedIndex].Values)
            //{
                //lstbxDicWords.Items.Add(wikiWord);
            //}

            if (lstbxDicNames.SelectedIndex >= 0)
                PutWordsToPanel(bot.Dictionary.Words[lstbxDicNames.SelectedIndex]);
        }        

    }
    




}